﻿using System;
using System.Configuration;
using System.Linq;
using System.Web.Security;
using System.Collections.Generic;
using System.ServiceModel;

using Cart;
using Encryption;
using BusinessObjects;
using DataObjects;

using ActionService.Criteria;
using ActionService.Messages;
using ActionService.MessageBase;
using ActionService.DataTransferObjectMapper;
using ActionService.ServiceContracts;

namespace ActionService.ServiceImplementations
{
    /// <summary>
    /// Main facade into Patterns in Action application.
    /// Important: Each Session has its own instance of this class (see ServiceBehavior Attribute).
    /// </summary>
    /// <remarks>
    /// Application Facade Pattern.
    /// </remarks>
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
    public class ActionService : IActionService
    {
        // Create default shipping
        private static readonly string _methodName = ConfigurationManager.AppSettings.Get("ShippingMethod");
        private static readonly ShippingMethod _defaultShippingMethod = (ShippingMethod)Enum.Parse(typeof(ShippingMethod), _methodName);

        // Create static data access objects
        private static readonly ICategoryDao _categoryDao = DataAccess.CategoryDao;
        private static readonly ICountryDao _countryDao = DataAccess.CountryDao;        
        private static readonly ICustomerDao _customerDao = DataAccess.CustomerDao;
        private static readonly IEmployeeDao _employeeDao = DataAccess.EmployeeDao;
        private static readonly IOrderDao _orderDao = DataAccess.OrderDao;
        private static readonly IOrderDetailDao _orderDetailDao = DataAccess.OrderDetailDao;
        private static readonly IPointDao _pointDao = DataAccess.PointDao;
        private static readonly IProductDao _productDao = DataAccess.ProductDao;
        private static readonly IProvinceDao _provinceDao = DataAccess.ProvinceDao;
        private static readonly IServiceDao _serviceDao = DataAccess.ServiceDao;
        private static readonly ISupplierDao _supplierDao = DataAccess.SupplierDao;
        private static readonly ITrafficDao _trafficDao = DataAccess.TrafficDao;
        private static readonly ITrafficTypeDao _trafficTypeDao = DataAccess.TrafficTypeDao;

        // Session state variables
        private string _accessToken;
        private ShoppingCart _shoppingCart; 
        private string _userName;
        
        /// <summary>
        /// Gets unique session based token that is valid for the duration of the session.
        /// </summary>
        /// <param name="request">Token request message.</param>
        /// <returns>Token response message.</returns>
        public TokenResponse GetToken(TokenRequest request)
        {
            var response = new TokenResponse( request.RequestId);

            // Validate client tag only
            if (!ValidRequest(request, response, Validate.ClientTag)) 
                return response;

            // Note: these are session based and expire when session expires.
            _accessToken = Guid.NewGuid().ToString();
            _shoppingCart = new ShoppingCart(_defaultShippingMethod);

            response.AccessToken = _accessToken;
            return response;
        }

        /// <summary>
        /// Login to application service.
        /// </summary>
        /// <param name="request">Login request message.</param>
        /// <returns>Login response message.</returns>
        public LoginResponse Login(LoginRequest request)
        {
            var response = new LoginResponse(request.RequestId);

            // Validate client tag and access token
            if (!ValidRequest(request, response, Validate.ClientTag | Validate.AccessToken))
                return response;

            if (!Membership.ValidateUser(request.UserName, request.Password))
            {
                response.Acknowledge = AcknowledgeType.Failure;
                response.Message = "Invalid username and/or password.";
                return response;
            }
           
            _userName = request.UserName;

            return response;
        }

        /// <summary>
        /// Logout from application service.
        /// </summary>
        /// <param name="request">Logout request message.</param>
        /// <returns>Login request message.</returns>
        public LogoutResponse Logout(LogoutRequest request)
        {
            var response = new LogoutResponse(request.RequestId);

            // Validate client tag and access token
            if (!ValidRequest(request, response, Validate.ClientTag | Validate.AccessToken))
                return response;

            _userName = null;

            return response;
        }

        /// <summary>
        /// Request shopping cart.
        /// </summary>
        /// <param name="request">Shopping cart request message.</param>
        /// <returns>Shopping cart response message.</returns>
        public CartResponse GetCart(CartRequest request)
        {
            var response = new CartResponse(request.RequestId);

            // Validate client tag and access token
            if (!ValidRequest(request, response, Validate.ClientTag | Validate.AccessToken))
                return response;

            // Always return recomputed shopping cart
            response.Cart = Mapper.ToDataTransferObject(_shoppingCart);

            return response;
        }

        /// <summary>
        /// Sets (add, edit, delete) shopping cart data.
        /// </summary>
        /// <param name="request">Shopping cart request message.</param>
        /// <returns>Shopping cart response message.</returns>
        public CartResponse SetCart(CartRequest request)
        {
            var response = new CartResponse(request.RequestId);

            // Validate client tag and access token
            if (!ValidRequest(request, response, Validate.ClientTag | Validate.AccessToken))
                return response;

            if (request.Action == "Read")
            {
                // Do nothing, just return cart    
            }
            else if (request.Action == "Create")
            {
                _shoppingCart.AddItem(request.CartItem.Id, request.CartItem.Name,
                    request.CartItem.Quantity, request.CartItem.UnitPrice);
            }
            else if (request.Action == "Update")
            {
                // Either shipping method or quantity requires update
                if (!string.IsNullOrEmpty(request.ShippingMethod))
                    _shoppingCart.ShippingMethod = (ShippingMethod)Enum.Parse(typeof(ShippingMethod), request.ShippingMethod);
                else
                    _shoppingCart.UpdateQuantity(request.CartItem.Id, request.CartItem.Quantity);
            }
            else if (request.Action == "Delete")
            {
                _shoppingCart.RemoveItem(request.CartItem.Id);
            }

            _shoppingCart.ReCalculate();
            response.Cart = Mapper.ToDataTransferObject(_shoppingCart);

            return response;
        }

        public CountryResponse GetCountries(CountryRequest request)
        {
            var response = new CountryResponse(request.RequestId);

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            var criteria = request.Criteria as CountryCriteria;
            string sort = criteria.SortExpression;

            if (request.LoadOptions.Contains("Countries"))
            {
                IEnumerable<Country> countries;
                if (!criteria.IncludeOrderStatistics)
                    countries = _countryDao.GetCountries(sort);
                //    //vietnh ""
                else
                    //countries = _countryDao.GetCountriesWithOrderStatistics(sort);
                    countries = _countryDao.GetCountries(sort);
                response.countries = countries.Select(c => Mapper.ToDataTransferObject(c)).ToList();
            }

            if (request.LoadOptions.Contains("Country"))
            {
                var country = _countryDao.GetCountry(criteria.CountryId);
                response.Country = Mapper.ToDataTransferObject(country);
            }
            return response;

        }

        public CountryResponse SetCountries(CountryRequest request)
        {
            var response = new CountryResponse(request.RequestId);

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            // Transform customer data transfer object to customer business object
            var country = Mapper.FromDataTransferObject(request.Country);

            // Validate customer business rules

            if (request.Action != "Delete")
            {
                if (!country.Validate())
                {
                    response.Acknowledge = AcknowledgeType.Failure;

                    foreach (string error in country.ValidationErrors)
                        response.Message += error + Environment.NewLine;

                    return response;
                }
            }

            // Run within the context of a database transaction. Currently commented out.
            // The Decorator Design Pattern. 
            //using (TransactionDecorator transaction = new TransactionDecorator())
            {
                if (request.Action == "Create")
                {
                    _countryDao.InsertCountry(country);
                    response.Country = Mapper.ToDataTransferObject(country);
                }
                else if (request.Action == "Update")
                {
                    _countryDao.UpdateCountry(country);
                    response.Country = Mapper.ToDataTransferObject(country);
                }
                else if (request.Action == "Delete")
                {
                    var criteria = request.Criteria as CountryCriteria;
                    var ctry = _countryDao.GetCountry(criteria.CountryId);

                    try
                    {
                        _countryDao.DeleteCountry(ctry);
                        response.RowsAffected = 1;
                    }
                    catch
                    {
                        response.RowsAffected = 0;
                    }
                }
            }

            return response;
        }

        /// <summary>
        /// Request customer data.
        /// </summary>
        /// <param name="request">Customer request message.</param>
        /// <returns>Customer response message.</returns>
        public CustomerResponse GetCustomers(CustomerRequest request)
        {
            try {
                var response = new CustomerResponse(request.RequestId);

                // Validate client tag, access token, and user credentials
                if (!ValidRequest(request, response, Validate.All))
                    return response;

                var criteria = request.Criteria as CustomerCriteria;
                string sort = criteria.SortExpression;

                if (request.LoadOptions.Contains("Customers"))
                {
                    IEnumerable<Customer> customers;
                    if (!criteria.IncludeOrderStatistics)
                        customers = _customerDao.GetCustomers(sort);
                    else
                        customers = _customerDao.GetCustomersWithOrderStatistics(sort);

                    response.Customers = customers.Select(c => Mapper.ToDataTransferObject(c)).ToList();
                }

                if (request.LoadOptions.Contains("Customer"))
                {
                    var customer = _customerDao.GetCustomer(criteria.CustomerId);
                    //if (request.LoadOptions.Contains("Orders"))
                    //    //vietnh
                    //    //customer.Orders = _orderDao.GetOrdersByCustomer(customer.CustomerId);
                    //    customer.Orders = _orderDao.GetOrdersByCustomer(customer.CustomerId);

                    response.Customer = Mapper.ToDataTransferObject(customer);
                }

                if (request.LoadOptions.Contains("Login"))
                {
                    var customer = _customerDao.CustomerLogin(criteria.UserName, criteria.PassWord);
                    //if (request.LoadOptions.Contains("Orders"))
                    //    //vietnh
                    //    //customer.Orders = _orderDao.GetOrdersByCustomer(customer.CustomerId);
                    //    customer.Orders = _orderDao.GetOrdersByCustomer(customer.CustomerId);

                    response.Customer = Mapper.ToDataTransferObject(customer[0]);
                }
                return response;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Set (add, update, delete) customer value.
        /// </summary>
        /// <param name="request">Customer request message.</param>
        /// <returns>Customer response message.</returns>
        public CustomerResponse SetCustomers(CustomerRequest request)
        {
            var response = new CustomerResponse(request.RequestId);

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            // Transform customer data transfer object to customer business object
            var customer = Mapper.FromDataTransferObject(request.Customer);

            // Validate customer business rules

            if (request.Action != "Delete")
            {
                if (!customer.Validate())
                {
                    response.Acknowledge = AcknowledgeType.Failure;

                    foreach (string error in customer.ValidationErrors)
                        response.Message += error + Environment.NewLine;

                    return response;
                }
            }

            // Run within the context of a database transaction. Currently commented out.
            // The Decorator Design Pattern. 
            //using (TransactionDecorator transaction = new TransactionDecorator())
            {
                if (request.Action == "Create")
                {
                    _customerDao.InsertCustomer(customer);
                    response.Customer = Mapper.ToDataTransferObject(customer);
                }
                else if (request.Action == "Update")
                {
                    _customerDao.UpdateCustomer(customer);
                    response.Customer = Mapper.ToDataTransferObject(customer);
                }
                else if (request.Action == "Delete")
                {
                    var criteria = request.Criteria as CustomerCriteria;
                    var cust = _customerDao.GetCustomer(criteria.CustomerId);

                    try
                    {
                        _customerDao.DeleteCustomer(cust);
                        response.RowsAffected = 1;
                    }
                    catch
                    {
                        response.RowsAffected = 0;
                    }
                }
            }

            return response;
        }

        public EmployeeResponse GetEmployees(EmployeeRequest request)
        {
            var response = new EmployeeResponse(request.RequestId);

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            var criteria = request.Criteria as EmployeeCriteria;
            string sort = criteria.SortExpression;

            if (request.LoadOptions.Contains("Employees"))
            {
                IEnumerable<Employee> employees;
                if (!criteria.IncludeOrderStatistics)
                    employees = _employeeDao.GetEmployee(sort);
                //    //vietnh ""
                else
                    //countries = _countryDao.GetCountriesWithOrderStatistics(sort);
                    employees = _employeeDao.GetEmployee(sort);
                response.Employees = employees.Select(c => Mapper.ToDataTransferObject(c)).ToList();
            }

            if (request.LoadOptions.Contains("Employee"))
            {
                var employee = _employeeDao.GetEmployee(criteria.EmployeeId, criteria.SupplierId);
                response.Employee = Mapper.ToDataTransferObject(employee);
            }
            return response;
        }

        public EmployeeResponse SetEmployees(EmployeeRequest request)
        {
            var response = new EmployeeResponse(request.RequestId);

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            // Transform employee data transfer object to customer business object
            var employee = Mapper.FromDataTransferObject(request.Employee);

            // Validate employee business rules

            if (request.Action != "Delete")
            {
                if (!employee.Validate())
                {
                    response.Acknowledge = AcknowledgeType.Failure;

                    foreach (string error in employee.ValidationErrors)
                        response.Message += error + Environment.NewLine;

                    return response;
                }
            }

            // Run within the context of a database transaction. Currently commented out.
            // The Decorator Design Pattern. 
            //using (TransactionDecorator transaction = new TransactionDecorator())
            {
                if (request.Action == "Create")
                {
                    _employeeDao.InsertEmployee(employee);
                    response.Employee = Mapper.ToDataTransferObject(employee);
                }
                else if (request.Action == "Update")
                {
                    _employeeDao.UpdateEmployee(employee);
                    response.Employee = Mapper.ToDataTransferObject(employee);
                }
                else if (request.Action == "Delete")
                {
                    var criteria = request.Criteria as EmployeeCriteria;
                    var emm = _employeeDao.GetEmployee(criteria.EmployeeId, criteria.SupplierId);

                    try
                    {
                        _employeeDao.DeleteEmployee(emm);
                        response.RowsAffected = 1;
                    }
                    catch
                    {
                        response.RowsAffected = 0;
                    }
                }
            }

            return response;
        }

        /// <summary>
        /// Request order data.
        /// </summary>
        /// <param name="request">Order request message.</param>
        /// <returns>Order response message.</returns>
        public OrderResponse GetOrders(OrderRequest request)
        {
            var response = new OrderResponse(request.RequestId);
            List<OrderDetail> OrderDetails = null;            
            
            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            var criteria = request.Criteria as OrderCriteria;

            if (request.LoadOptions.Contains("Order"))
            {
                var order = _orderDao.GetOrder(criteria.OrderId);
                List<int> ChairList = new List<int>();
                List<string> ChairNameList = new List<string>();                
                List<int> StatusList = new List<int>();
                List<decimal> PriceList = new List<decimal>();
                List<int> OrderDetailIdList = new List<int>(); 
                int CategoryId = 0;

               
                    OrderDetails = _orderDetailDao.GetOrderDetails(order.OrderId);

                response.Order = Mapper.ToDataTransferObject(order);

                if (OrderDetails.Count > 0)
                {
                    for(int i = 0;i<OrderDetails.Count;i++)
                    {
                         ChairList.Add(OrderDetails[i].ProductId);       
                         ChairNameList.Add(OrderDetails[i].ProductName);
                         StatusList.Add(OrderDetails[i].Status);
                         PriceList.Add(OrderDetails[i].UnitPrice);
                         OrderDetailIdList.Add(OrderDetails[i].OrderDetailId);
                         CategoryId=OrderDetails[i].CategoryId;
                    }
                }
                response.CategoryId = CategoryId;
                response.ChairList = ChairList;
                response.ChairNameList = ChairNameList;
                response.StatusList = StatusList;
                response.PriceList = PriceList;
                response.OrderDetailIdList = OrderDetailIdList;
            }

            if (request.LoadOptions.Contains("Orders"))
            {
                List<Order> orders = new List<Order>();                
                orders = _orderDao.GetOrders(criteria.CustomerId,criteria.SupplierId,criteria.DateFrom,criteria.DateThru,criteria.Status);                
                response.Orders = Mapper.ToDataTransferObjects(orders);
            }

            return response;
        }

        // Not implemented. No orders are taken.
        public OrderResponse SetOrders(OrderRequest request)
        {
            var response = new OrderResponse(request.RequestId);

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            // Transform Order data transfer object to Order business object
            var order = Mapper.FromDataTransferObject(request.Order);

            // Validate Order business rules

            if (request.Action != "Delete")
            {
                if (!order.Validate())
                {
                    response.Acknowledge = AcknowledgeType.Failure;

                    foreach (string error in order.ValidationErrors)
                        response.Message += error + Environment.NewLine;

                    return response;
                }
            }

            // Run within the context of a database transaction. Currently commented out.
            // The Decorator Design Pattern. 
            //using (TransactionDecorator transaction = new TransactionDecorator())
            {
                if (request.Action == "Create")
                {
                    _orderDao.InsertOrder(order);
                    if (request.ChairList.Count > 0)
                    {
                        for (int i = 0; i < request.ChairList.Count; i++)
                        {
                            OrderDetail Detail = new OrderDetail();
                            Detail.OrderId = order.OrderId;
                            Detail.CategoryId = request.CategoryId;
                            Detail.ProductId = request.ChairList[i];
                            Detail.ProductName = request.ChairNameList[i];
                            Detail.Quantity = 1;
                            Detail.Status = 0;
                            Detail.UnitPrice = 0;
                            Detail.Version = "0";
                            _orderDetailDao.InsertOrderDetail(Detail);
                        }
                    }
                    response.Order = Mapper.ToDataTransferObject(order);
                }
                else if (request.Action == "Update")
                {
                    _orderDao.UpdateOrder(order);

                    if (request.ChairList.Count > 0)
                    {
                        for (int i = 0; i < request.ChairList.Count; i++)
                        {
                            OrderDetail Detail = new OrderDetail();
                            Detail.ProductId = request.ChairList[i];
                            Detail.OrderId = order.OrderId;
                            Detail.Status = 1;
                            _orderDetailDao.UpdateOrderDetail(Detail);
                        }
                    }
                    response.Order = Mapper.ToDataTransferObject(order);
                }
                else if (request.Action == "Delete")
                {
                    var criteria = request.Criteria as OrderCriteria;
                    var ord = _orderDao.GetOrder(criteria.OrderId);
                    //OrderDetail orderDetail = new OrderDetail();
                    //orderDetail.OrderId = criteria.OrderId;
                    try
                    {
                        _orderDetailDao.DeleteOrderDetailByOrderId(criteria.OrderId);
                        _orderDao.DeleteOrder(ord);
                        response.RowsAffected = 1;
                    }
                    catch
                    {
                        response.RowsAffected = 0;
                    }
                }
            }

            return response;
        }

        public OrderDetailResponse GetOrderDetails(OrderDetailRequest request)
        {
            var response = new OrderDetailResponse(request.RequestId);

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            var criteria = request.Criteria as OrderDetailCriteria;
            var OrderId = request.OrderId;
            string sort = criteria.SortExpression;

            if (request.LoadOptions.Contains("OrderDetails"))
            {
                IEnumerable<OrderDetail> orderDetails;
                if (!criteria.IncludeOrderStatistics)
                    orderDetails = _orderDetailDao.GetOrderDetails(OrderId);
                //    //vietnh ""
                else
                    //countries = _countryDao.GetCountriesWithOrderStatistics(sort);
                    orderDetails = _orderDetailDao.GetOrderDetails(OrderId);
                response.orderDetails = orderDetails.Select(c => Mapper.ToDataTransferObject(c)).ToList();
            }

            if (request.LoadOptions.Contains("OrderDetail"))
            {
                var orderDetail = _orderDetailDao.GetOrderDetail(criteria.OrderDetailId);
                response.orderDetail = Mapper.ToDataTransferObject(orderDetail);
            }
            return response;
        }

        public OrderDetailResponse SetOrderDetails(OrderDetailRequest request)
        {
            var response = new OrderDetailResponse(request.RequestId);

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            // Transform OrderDetail data transfer object to Order business object
            var orderDetail = Mapper.FromDataTransferObject(request.OrderDetail);

            // Validate Order business rules

            if (request.Action != "Delete")
            {
                if (!orderDetail.Validate())
                {
                    response.Acknowledge = AcknowledgeType.Failure;

                    foreach (string error in orderDetail.ValidationErrors)
                        response.Message += error + Environment.NewLine;

                    return response;
                }
            }

            // Run within the context of a database transaction. Currently commented out.
            // The Decorator Design Pattern. 
            //using (TransactionDecorator transaction = new TransactionDecorator())
            {
                if (request.Action == "Create")
                {
                    _orderDetailDao.InsertOrderDetail(orderDetail);
                    response.orderDetail = Mapper.ToDataTransferObject(orderDetail);
                }
                else if (request.Action == "Update")
                {
                    _orderDetailDao.UpdateOrderDetail(orderDetail);
                    response.orderDetail = Mapper.ToDataTransferObject(orderDetail);
                }
                else if (request.Action == "Delete")
                {
                    var criteria = request.Criteria as OrderDetailCriteria;
                    var ordDe = _orderDetailDao.GetOrderDetail(criteria.OrderDetailId);

                    try
                    {
                        _orderDetailDao.DeleteOrderDetail(ordDe);
                        response.RowsAffected = 1;
                    }
                    catch
                    {
                        response.RowsAffected = 0;
                    }
                }
            }

            return response;
        }

        public PointResponse GetPoints(PointRequest request)
        {
            var response = new PointResponse(request.RequestId);

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            var criteria = request.Criteria as PointCriteria;
            string sort = criteria.SortExpression;

            if (request.LoadOptions.Contains("Points"))
            {
                IEnumerable<Point> points;
                points = _pointDao.GetPoints(criteria.ProvinceId,sort);
                response.Points = points.Select(p => Mapper.ToDataTransferObject(p)).ToList();
            }

            if (request.LoadOptions.Contains("Point"))
            {
                var point = _pointDao.GetPoint(criteria.PointId);
                response.Point = Mapper.ToDataTransferObject(point);
            }
            return response;
        }

        public PointResponse SetPoints(PointRequest request)
        {
            var response = new PointResponse(request.RequestId);

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            // Transform Point data transfer object to Point business object
            var point = Mapper.FromDataTransferObject(request.Point);

            // Validate employee business rules

            if (request.Action != "Delete")
            {
                if (!point.Validate())
                {
                    response.Acknowledge = AcknowledgeType.Failure;

                    foreach (string error in point.ValidationErrors)
                        response.Message += error + Environment.NewLine;

                    return response;
                }
            }

            // Run within the context of a database transaction. Currently commented out.
            // The Decorator Design Pattern. 
            //using (TransactionDecorator transaction = new TransactionDecorator())
            {
                if (request.Action == "Create")
                {
                    _pointDao.InsertPoint(point);
                    response.Point = Mapper.ToDataTransferObject(point);
                }
                else if (request.Action == "Update")
                {
                    _pointDao.UpdatePoint(point);
                    response.Point = Mapper.ToDataTransferObject(point);
                }
                else if (request.Action == "Delete")
                {
                    var criteria = request.Criteria as PointCriteria;
                    var pnt = _pointDao.GetPoint(criteria.PointId);

                    try
                    {
                        _pointDao.DeletePoint(pnt);
                        response.RowsAffected = 1;
                    }
                    catch
                    {
                        response.RowsAffected = 0;
                    }
                }
            }

            return response;
        }

        /// <summary>
        /// Requests product data.
        /// </summary>
        /// <param name="request">Product request message.</param>
        /// <returns>Product response message.</returns>
        public ProductResponse GetProducts(ProductRequest request)
        {
            var response = new ProductResponse(request.RequestId);

            // Validate client tag and access token
            if (!ValidRequest(request, response, Validate.ClientTag | Validate.AccessToken))
                return response;

            var criteria = request.Criteria as ProductCriteria;

            if (request.LoadOptions.Contains("Categories"))
            {
                var categories = _categoryDao.GetCategories();
                response.Categories = Mapper.ToDataTransferObjects(categories);
            }

            if (request.LoadOptions.Contains("Products"))
            {
                var products = _productDao.GetProductsByCategory(criteria.CategoryId, criteria.SortExpression);
                response.Products = Mapper.ToDataTransferObjects(products);
            }

            if (request.LoadOptions.Contains("Product"))
            {
                var product = _productDao.GetProduct(criteria.ProductId, criteria.CategoryId);

                product.CategoryId = _categoryDao.GetCategoryByProduct(criteria.ProductId);

                response.Product = Mapper.ToDataTransferObject(product);
            }

            if (request.LoadOptions.Contains("Search"))
            {
                var products = _productDao.SearchProducts(criteria.CategoryId, criteria.SortExpression);

                response.Products = Mapper.ToDataTransferObjects(products);
            }
            return response;
        }

        public ProductResponse SetProducts(ProductRequest request)
        {
            var response = new ProductResponse(request.RequestId);

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            // Transform product data transfer object to product business object
            var product = Mapper.FromDataTransferObject(request.Product);

            // Validate customer business rules

            if (request.Action != "Delete")
            {
                if (!product.Validate())
                {
                    response.Acknowledge = AcknowledgeType.Failure;

                    foreach (string error in product.ValidationErrors)
                        response.Message += error + Environment.NewLine;

                    return response;
                }
            }

            // Run within the context of a database transaction. Currently commented out.
            // The Decorator Design Pattern. 
            //using (TransactionDecorator transaction = new TransactionDecorator())
            {
                if (request.Action == "Create")
                {
                    _productDao.InsertProduct(product);
                    response.Product = Mapper.ToDataTransferObject(product);
                }
                //// TAIPM : 09/01/2011
                //else if (request.Action == "Book")
                //{
                //    _productDao.Book(product.ProductId, null);
                //    response.Product = Mapper.ToDataTransferObject(product);                    
                //}
                else if (request.Action == "Update")
                {
                    _productDao.UpdateProduct(product);
                    response.Product = Mapper.ToDataTransferObject(product);
                }
                else if (request.Action == "Delete")
                {
                    var criteria = request.Criteria as ProductCriteria;
                    var cust = _customerDao.GetCustomer(criteria.ProductId);

                    try
                    {
                        _productDao.DeleteProduct(product);
                        response.RowsAffected = 1;
                    }
                    catch
                    {
                        response.RowsAffected = 0;
                    }
                }
                else if (request.Action == "DeleteByCategoryId")
                {
                    var criteria = request.Criteria as ProductCriteria;
                    
                    try
                    {
                        _productDao.DeleteProductByCategoryId(criteria.CategoryId);
                        response.RowsAffected = 1;
                    }
                    catch
                    {
                        response.RowsAffected = 0;
                    }
                }
            }


            return response;
        }

        public ProvinceResponse GetProvinces(ProvinceRequest request)
        {
            var response = new ProvinceResponse(request.RequestId);

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            var criteria = request.Criteria as ProvinceCriteria;
            string sort = criteria.SortExpression;

            if (request.LoadOptions.Contains("Provinces"))
            {
                IEnumerable<Province> provinces;
                if (!criteria.IncludeOrderStatistics)
                    provinces = _provinceDao.GetProvinces(sort);
                //    //vietnh ""
                else
                    //countries = _countryDao.GetCountriesWithOrderStatistics(sort);
                    provinces = _provinceDao.GetProvinces(sort);
                response.Provinces = provinces.Select(p => Mapper.ToDataTransferObject(p)).ToList();
            }

            if (request.LoadOptions.Contains("Province"))
            {
                var province = _provinceDao.GetProvince(criteria.ProvinceId);
                response.Province = Mapper.ToDataTransferObject(province);
            }
            return response;
        }

        public ProvinceResponse SetProvinces(ProvinceRequest request)
        {
            var response = new ProvinceResponse(request.RequestId);

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            // Transform Point data transfer object to Point business object
            var province = Mapper.FromDataTransferObject(request.Province);

            // Validate employee business rules

            if (request.Action != "Delete")
            {
                if (!province.Validate())
                {
                    response.Acknowledge = AcknowledgeType.Failure;

                    foreach (string error in province.ValidationErrors)
                        response.Message += error + Environment.NewLine;

                    return response;
                }
            }

            // Run within the context of a database transaction. Currently commented out.
            // The Decorator Design Pattern. 
            //using (TransactionDecorator transaction = new TransactionDecorator())
            {
                if (request.Action == "Create")
                {
                    _provinceDao.InsertProvince(province);
                    response.Province = Mapper.ToDataTransferObject(province);
                }
                else if (request.Action == "Update")
                {
                    _provinceDao.UpdateProvince(province);
                    response.Province = Mapper.ToDataTransferObject(province);
                }
                else if (request.Action == "Delete")
                {
                    var criteria = request.Criteria as ProvinceCriteria;
                    var prv = _provinceDao.GetProvince(criteria.ProvinceId);

                    try
                    {
                        _provinceDao.DeleteProvince(prv);
                        response.RowsAffected = 1;
                    }
                    catch
                    {
                        response.RowsAffected = 0;
                    }
                }
            }

            return response;
        }

        public ServiceResponse GetServices(ServiceRequest request)
        {
            var response = new ServiceResponse(request.RequestId);

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            var criteria = request.Criteria as ServiceCriteria;
            string sort = criteria.SortExpression;

            if (request.LoadOptions.Contains("Services"))
            {
                IEnumerable<Service> services;
                if (!criteria.IncludeOrderStatistics)
                    services = _serviceDao.GetServices(sort);
                //    //vietnh ""
                else
                    //countries = _countryDao.GetCountriesWithOrderStatistics(sort);
                    services = _serviceDao.GetServices(sort);
                response.Services = services.Select(s => Mapper.ToDataTransferObject(s)).ToList();
            }

            if (request.LoadOptions.Contains("Service"))
            {
                var service = _serviceDao.GetService(criteria.ServiceId);
                response.Service = Mapper.ToDataTransferObject(service);
            }
            return response;
        }

        public ServiceResponse SetServices(ServiceRequest request)
        {
            var response = new ServiceResponse(request.RequestId);

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            // Transform service data transfer object to service business object
            var service = Mapper.FromDataTransferObject(request.Service);

            // Validate service business rules

            if (request.Action != "Delete")
            {
                if (!service.Validate())
                {
                    response.Acknowledge = AcknowledgeType.Failure;

                    foreach (string error in service.ValidationErrors)
                        response.Message += error + Environment.NewLine;

                    return response;
                }
            }

            // Run within the context of a database transaction. Currently commented out.
            // The Decorator Design Pattern. 
            //using (TransactionDecorator transaction = new TransactionDecorator())
            {
                if (request.Action == "Create")
                {
                    _serviceDao.InsertService(service);
                    response.Service = Mapper.ToDataTransferObject(service);
                }
                else if (request.Action == "Update")
                {
                    _serviceDao.UpdateService(service);
                    response.Service = Mapper.ToDataTransferObject(service);
                }
                else if (request.Action == "Delete")
                {
                    var criteria = request.Criteria as ServiceCriteria;
                    var srv = _serviceDao.GetService(criteria.ServiceId);

                    try
                    {
                        _serviceDao.DeleteService(srv);
                        response.RowsAffected = 1;
                    }
                    catch
                    {
                        response.RowsAffected = 0;
                    }
                }
            }

            return response;
        }

        public SupplierResponse GetSuppliers(SupplierRequest request)
        {
            var response = new SupplierResponse(request.RequestId);

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            var criteria = request.Criteria as SupplierCriteria;
            string sort = criteria.SortExpression;

            if (request.LoadOptions.Contains("Suppliers"))
            {
                IEnumerable<Supplier> suppliers;
                if (!criteria.IncludeOrderStatistics)
                    suppliers = _supplierDao.GetSuppliers(sort);
                //    //vietnh ""
                else
                    //countries = _countryDao.GetCountriesWithOrderStatistics(sort);
                    suppliers = _supplierDao.GetSuppliers(sort);
                response.Suppliers = suppliers.Select(s => Mapper.ToDataTransferObject(s)).ToList();
            }

            if (request.LoadOptions.Contains("Supplier"))
            {
                var supplier = _supplierDao.GetSupplier(criteria.SupplierId);
                response.Supplier = Mapper.ToDataTransferObject(supplier);
            }

            if (request.LoadOptions.Contains("Login"))
            {
                var supplier = _supplierDao.SupplierLogin(criteria.UserName,criteria.PassWord);
                response.Suppliers = supplier.Select(s => Mapper.ToDataTransferObject(s)).ToList();
            }
            return response;
        }

        public SupplierResponse SetSuppliers(SupplierRequest request)
        {
            var response = new SupplierResponse(request.RequestId);

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            // Transform service data transfer object to service business object
            var supplier = Mapper.FromDataTransferObject(request.Supplier);

            // Validate service business rules

            if (request.Action != "Delete")
            {
                if (!supplier.Validate())
                {
                    response.Acknowledge = AcknowledgeType.Failure;

                    foreach (string error in supplier.ValidationErrors)
                        response.Message += error + Environment.NewLine;

                    return response;
                }
            }

            // Run within the context of a database transaction. Currently commented out.
            // The Decorator Design Pattern. 
            //using (TransactionDecorator transaction = new TransactionDecorator())
            {
                if (request.Action == "Create")
                {
                    _supplierDao.InsertSupplier(supplier);
                    response.Supplier = Mapper.ToDataTransferObject(supplier);
                }
                else if (request.Action == "Update")
                {
                    _supplierDao.UpdateSupplier(supplier);
                    response.Supplier = Mapper.ToDataTransferObject(supplier);
                }
                else if (request.Action == "Delete")
                {
                    var criteria = request.Criteria as SupplierCriteria;
                    var supp = _supplierDao.GetSupplier(criteria.SupplierId);

                    try
                    {
                        _supplierDao.DeleteSupplier(supp);
                        response.RowsAffected = 1;
                    }
                    catch
                    {
                        response.RowsAffected = 0;
                    }
                }
            }

            return response;
        }

        public TrafficResponse GetTraffics(TrafficRequest request)
        {
            var response = new TrafficResponse(request.RequestId);

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            var criteria = request.Criteria as TrafficCriteria;
            string sort = criteria.SortExpression;

            if (request.LoadOptions.Contains("Traffics"))
            {
                IEnumerable<Traffic> traffics;
                if (!criteria.IncludeOrderStatistics)
                    traffics = _trafficDao.GetTraffic(sort);
                //    //vietnh ""
                else
                    //countries = _countryDao.GetCountriesWithOrderStatistics(sort);
                    traffics = _trafficDao.GetTraffic(sort);
                response.Traffics = traffics.Select(t => Mapper.ToDataTransferObject(t)).ToList();
            }

            if (request.LoadOptions.Contains("Traffic"))
            {
                var traffic = _trafficDao.GetTraffic(criteria.TrafficId, criteria.SupplierID);
                response.Traffic = Mapper.ToDataTransferObject(traffic);
            }
            return response;
        }

        public TrafficResponse SetTraffics(TrafficRequest request)
        {
            var response = new TrafficResponse(request.RequestId);

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            // Transform service data transfer object to service business object
            var traffic = Mapper.FromDataTransferObject(request.Traffic);

            // Validate service business rules

            if (request.Action != "Delete")
            {
                if (!traffic.Validate())
                {
                    response.Acknowledge = AcknowledgeType.Failure;

                    foreach (string error in traffic.ValidationErrors)
                        response.Message += error + Environment.NewLine;

                    return response;
                }
            }

            // Run within the context of a database transaction. Currently commented out.
            // The Decorator Design Pattern. 
            //using (TransactionDecorator transaction = new TransactionDecorator())
            {
                if (request.Action == "Create")
                {
                    _trafficDao.InsertTraffic(traffic);
                    response.Traffic = Mapper.ToDataTransferObject(traffic);
                }
                else if (request.Action == "Update")
                {
                    _trafficDao.UpdateTraffic(traffic);
                    response.Traffic = Mapper.ToDataTransferObject(traffic);
                }
                else if (request.Action == "Delete")
                {
                    var criteria = request.Criteria as TrafficCriteria;
                    var trf = _trafficDao.GetTraffic(criteria.TrafficId, criteria.SupplierID);

                    try
                    {
                        _trafficDao.DeleteTraffic(trf);
                        response.RowsAffected = 1;
                    }
                    catch
                    {
                        response.RowsAffected = 0;
                    }
                }
            }

            return response;
        }

        public TrafficTypeResponse GetTrafficTypes(TrafficTypeRequest request)
        {
            var response = new TrafficTypeResponse(request.RequestId);

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            var criteria = request.Criteria as TrafficTypeCriteria;
            string sort = criteria.SortExpression;

            if (request.LoadOptions.Contains("TrafficTypes"))
            {
                IEnumerable<TrafficType> trafficTypes;
                if (!criteria.IncludeOrderStatistics)
                    trafficTypes = _trafficTypeDao.GetTrafficType(sort);
                //    //vietnh ""
                else
                    //countries = _countryDao.GetCountriesWithOrderStatistics(sort);
                    trafficTypes = _trafficTypeDao.GetTrafficType(sort);
                response.TrafficTypes = trafficTypes.Select(t => Mapper.ToDataTransferObject(t)).ToList();
            }

            if (request.LoadOptions.Contains("TrafficType"))
            {
                var trafficType = _trafficTypeDao.GetTrafficType(criteria.TrafficTypeId);
                response.TrafficType = Mapper.ToDataTransferObject(trafficType);
            }
            return response;
        }

        public TrafficTypeResponse SetTrafficTypes(TrafficTypeRequest request)
        {
            var response = new TrafficTypeResponse(request.RequestId);

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            // Transform service data transfer object to service business object
            var trafficType = Mapper.FromDataTransferObject(request.TrafficType);

            // Validate service business rules

            if (request.Action != "Delete")
            {
                if (!trafficType.Validate())
                {
                    response.Acknowledge = AcknowledgeType.Failure;

                    foreach (string error in trafficType.ValidationErrors)
                        response.Message += error + Environment.NewLine;

                    return response;
                }
            }

            // Run within the context of a database transaction. Currently commented out.
            // The Decorator Design Pattern. 
            //using (TransactionDecorator transaction = new TransactionDecorator())
            {
                if (request.Action == "Create")
                {
                    _trafficTypeDao.InsertTrafficType(trafficType);
                    response.TrafficType = Mapper.ToDataTransferObject(trafficType);
                }
                else if (request.Action == "Update")
                {
                    _trafficTypeDao.UpdateTrafficType(trafficType);
                    response.TrafficType = Mapper.ToDataTransferObject(trafficType);
                }
                else if (request.Action == "Delete")
                {
                    var criteria = request.Criteria as TrafficTypeCriteria;
                    var trft = _trafficTypeDao.GetTrafficType(criteria.TrafficTypeId);

                    try
                    {
                        _trafficTypeDao.DeleteTrafficType(trft);
                        response.RowsAffected = 1;
                    }
                    catch
                    {
                        response.RowsAffected = 0;
                    }
                }
            }

            return response;
        }

        public CategoryResponse SetCategories(CategoryRequest request)
        {
            var response = new CategoryResponse(request.RequestId);

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            // Transform customer data transfer object to customer business object
            var category = Mapper.FromDataTransferObject(request.Category);

            // Validate customer business rules

            if (request.Action != "Delete")
            {
                if (!category.Validate())
                {
                    response.Acknowledge = AcknowledgeType.Failure;

                    foreach (string error in category.ValidationErrors)
                        response.Message += error + Environment.NewLine;

                    return response;
                }
            }

            // Run within the context of a database transaction. Currently commented out.
            // The Decorator Design Pattern. 
            //using (TransactionDecorator transaction = new TransactionDecorator())
            {
                if (request.Action == "Create")
                {
                    _categoryDao.InsertCategory(category);
                    response.Category = Mapper.ToDataTransferObject(category);
                }
                else if (request.Action == "Update")
                {
                    _categoryDao.UpdateCategory(category);
                    response.Category = Mapper.ToDataTransferObject(category);
                }
                else if (request.Action == "Delete")
                {
                    var criteria = request.Criteria as CategoryCriteria;
                    var cate = _categoryDao.GetCategory(criteria.CategoryId);

                    try
                    {
                        _categoryDao.DeleteCategory(cate);
                        response.RowsAffected = 1;
                    }
                    catch
                    {
                        response.RowsAffected = 0;
                    }
                }
            }

            return response;
        }

        public CategoryResponse GetCategories(CategoryRequest request)
        {
            var response = new CategoryResponse(request.RequestId);

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            var criteria = request.Criteria as CategoryCriteria;
            string sort = criteria.SortExpression;

            if (request.LoadOptions.Contains("Categories"))
            {
                IEnumerable<Category> categories;
                if (!criteria.IncludeOrderStatistics)
                    categories = _categoryDao.GetCategories();
                //    //vietnh ""
                else
                    //countries = _countryDao.GetCountriesWithOrderStatistics(sort);
                    categories = _categoryDao.GetCategories();
                response.Categories = categories.Select(c => Mapper.ToDataTransferObject(c)).ToList();
            }

            if (request.LoadOptions.Contains("Category"))
            {
                var category = _categoryDao.GetCategory(criteria.CategoryId);
                response.Category = Mapper.ToDataTransferObject(category);
            }

            if (request.LoadOptions.Contains("Search"))
            {
                var categories = _categoryDao.SearchCategories(criteria.DateFrom, criteria.DateTo,
                    criteria.FirstPoint, criteria.LastPoint, (criteria.SupplierId == null) ? 0 : criteria.SupplierId, (criteria.TrafficId == null) ? 0 : criteria.TrafficId, criteria.SortExpression);

                response.Categories = Mapper.ToDataTransferObjects(categories);
            }

            return response;
        }

        /// <summary>
        /// Validate 3 security levels for a request: ClientTag, AccessToken, and User Credentials
        /// </summary>
        /// <param name="request">The request message.</param>
        /// <param name="response">The response message.</param>
        /// <param name="validate">The validation that needs to take place.</param>
        /// <returns></returns>
        private bool ValidRequest(RequestBase request, ResponseBase response, Validate validate)
        {
            // Validate Client Tag. 
            // Hardcoded here. In production this should query a 'client' table in a database.
            if ((Validate.ClientTag & validate) == Validate.ClientTag)
            {
                if (request.ClientTag != "ABC123")
                {
                    response.Acknowledge = AcknowledgeType.Failure;
                    response.Message = "Unknown Client Tag";
                    return false;
                }
            }


            // Validate access token
            if ((Validate.AccessToken & validate) == Validate.AccessToken)
            {
                //if (request.AccessToken != _accessToken)
                //{
                //    response.Acknowledge = AcknowledgeType.Failure;
                //    response.Message = "Invalid or expired AccessToken. Call GetToken()";
                //    return false;
                //}
            }

            // Validate user credentials
            if ((Validate.UserCredentials & validate) == Validate.UserCredentials)
            {
                //if (_userName == null) 
                //{
                //    response.Acknowledge = AcknowledgeType.Failure;
                //    response.Message = "Please login and provide user credentials before accessing these methods.";
                //    return false;
                //}
            }


            return true;
        }

        #region Primary key encryption methods. Not currently used.

        /// <summary>
        /// Encrypts internal identifier before sending it out to client.
        /// Private helper method.
        /// </summary>
        /// <param name="id">Identifier to be encrypted.</param>
        /// <param name="tableName">Database table in which identifier resides.</param>
        /// <returns>Encrypted stringified identifier.</returns>
        private string EncryptId(int id, string tableName)
        {
            string s = id.ToString() + "|" + tableName;
            return Crypto.ActionEncrypt(s);
        }

        /// <summary>
        /// Decrypts identifiers that come back from client.
        /// Private helper method.
        /// </summary>
        /// <param name="sid">Stringified, encrypted identifier.</param>
        /// <returns>Internal identifier.</returns>
        private int DecryptId(string sid)
        {
            string s = Crypto.ActionDecrypt(sid);
            s = s.Substring(0, s.IndexOf("|"));
            return int.Parse(s);
        }

        #endregion

        /// <summary>
        /// Validation options enum. Used in validation of messages.
        /// </summary>
        [Flags]
        private enum Validate
        {
            ClientTag = 0x0001,
            AccessToken = 0x0002,
            UserCredentials = 0x0004,
            All = ClientTag | AccessToken | UserCredentials
        }        
    }
}
